     -=( 7A69#11 )=--=( art16 )=--=( Bypass checksums )=--=( Marconi )=-

Bueno, antes de nada, presentarme.... respondo al nick de Marconi y soy uno
de los componentes de la pagina:
            http://members.xoom.com/el_liceo
Y cualquier duda, comentario, o lo que sea lo podeis mandar a:
            inocram@yahoo.com
Soy una de las personas mas despistadas que jamas ha pisado la tierra, asi
que es muy posible que haya tenido alguna equivocacion (o muchas).
Agradeceria a cualquiera que viese algun error me enviase un mail
diciendomelo. Pido perdon anticipadamente por cualkier error, asi como faltas
de ortografia, desvarios mentales, etc.

Y una vez hechas las presentaciones, vamos al tema que nos ocupa.
En este caso vamos a tratar de crackear un programa k, la verdad, no vale ni
para tomar por culo, pero lo importante en este caso no es el ke vamos a
crackear, sino el como lo vamos a hacer. Veremos primero ke el encontrar una
solucion para evitar la restriccion de tiempo es muy sencillo pero al
intentar parchear el ejecutable nos encontramos con ke el programa deja de
funcionar. Y he aki el verdadero objetivo de este articulo, buscar soluciones
ha este problema. Se proponen tres posibles soluciones k nos llevan con mayor
o menor esfuerzo al crackeo satisfactorio del programa... creo k esto es
suficiente para k os hagais una idea del contenido ke vais a encontrar en
este articulo....pasemos al indice :)

1.- Lista de cosas ke necesitamos.
2.- La victima.
        2.1.- Presentacion de la victima.
        2.2.- Acerca de T.U.G. by [yAtEs], agosto del 99.
3.- El problema del periodo de prueba.
        3.1.- Primer intento fallido.
        3.2.- GetSystemTime(), encontramos el salto condicional.
        3.3.- Parcheamos el ejecutable y....plof!
4.- El Checksum. La modificacion del ejecutable ha sido detectada.
        4.1.- Solucion 1... El loader.
                4.1.1.- Funciones ke es necesario conocer.
                        4.1.1.1.- CreateProcess();
                        4.1.1.2.- WriteProcessMemory();
                        4.1.1.3.- FlushInstructionCache();
                        4.1.1.4.- ResumeThread();
                4.1.2.- El codigo de nuestro loader.
        4.2.- Solucion 2... Introduciendo codigo propio en un ejecutable.
                4.2.1.- Buscando un punto de atake.
                4.2.2.- Haciendolo a mano.
                4.2.3.- Usando el Code Snippet Creator.
                        4.2.3.1.- Datos ke necesitamos.
                        4.2.3.2.- Escribiendo e introduciendo el recorte.                        
                4.2.4.- Consideraciones finales.
        4.3.- Solucion 3... Modificando la rutina de proteccion.
5.- Esto es todo amigos.



1.- LISTA DE COSAS KE NECESITAMOS.

Esta lista esta en riguroso desorden, de las cosas ke utiliaremos a lo largo
de este articulo :)

        - Necesitamos un ensamblador para Win32. Yo utilizo el:
                Microsoft (R) Macro Assembler Version 6.14.8444
                Microsoft (R) Incremental Linker Version 5.12.8078
        Eres libre de usar el ensamblador ke a ti te de la gana :)

        - Un desensamblador. Yo use el W32Dasm V 8.93
        Ahora mismo no recuerdo si el desensamblador es o no imprescindible,
        pero si recuerdo haberlo usado para algo. Tu usa el k te venga en
        gana.

        - Un Debugger. Yo use nuestro kerido SoftICE version 4.0.5(build 334)
        Como antes, usa el k kieras :)

        - Un editor de PE, yo use el ProcDump32, de G-RoM, Lorian y Stone

        - Un editor hexadecimal. En mi caso, use el UltraEdit-32

        - El Code Snippet Creator, en mi caso la veriosn 1.05 build 2,
        programa de Iczelion. Este programa es prescindible.

        - El  r!sc's process patcher v1.5.1... este programa realmente no se
        usa, solo se comenta una cosa, pero es totalmente prescindible.

        - El MuseArc, version ??? posi, casi k el prgrama victima si ke lo
        vamos a necesitar

        - Una botella de autentico Vodka ruso, y algo para mezclar,
        preferiblemento sprite, aunke limon tambien vale. Tambien
        necesitaremos hielo y pajitas.Esto tambien es prescindible, pero muy
        recomendable.






2.- LA VICTIMA.

 2.1.- PRESENTACION DE LA VICTIMA.

 En este caso he decidido que nuestra victima sera un programa llamado
 museArc. En concreto este programa es un reproductor de mpeg diseado para
 windows95 y WindowsNT, estamos hablando de la version 4.6.97.8 beta. (esa
 version segun el programa de instalacion, segun el  archivo readme.txt que
 viene junto con la aplicacion es la version 4.6.97.9, y segun el archivo de
 ayuda es la version 4.5.... bueno, parece ke no lo tenian muy claro)... de
 todas formas lo ke menos me importa es la version, yo lo k kiero es hacerlo
 rular.... :)

 2.2.- ACERCA DE T.U.G. by [yAtEs], AGOSTO DEL 99.

 Pues aki tengo k komentar unas cuantas cosas. El caso es ke este programa
 fue tratado ya hace tiempo, concretamente en agosto del 99, por [yAtEs].
 Este era uno de los programas ke se crackeaban en T.U.G., the ultimate guide
 to cracking for newbies, ke komo su nombre indica es una guia de cracking
 orientada a los principiantes en este noble arte ;). En el estudio ke [yAtEs]
 hacia de este programa, llegaba a la misma conclusion ke yo. Encontraba el
 salto condicional ke komprobaba si el periodo de pruebas habia expirado, y
 lo parcheaba dentro del ejecutable para ke nunca fuese asi ( cambiaba el
 salto condicional por un salto incondicional, lo veremos mas adelante). Una
 vez hecho esto el programa dejaba de funcionar, como ya he adelantado.
 La solucion escogida en este caso, fue la generacion de un loader usando
 para ello el programa "R!SC'S Proccess Patcher". Y para el ke no sepa de ke
 estoy habladno, ke no se preocupe, porke mas adelante explicare ke es esto
 de un loader y haremos nuestro propio loader para este programa, como no,
 en ensamblador. El  R!SC'S Proccess Patcher crea loaders para procesos Win32
 a partir de un simple script. Estos scripts se identifican por su extension
 .rpp, y se ponen en el mismo directorio ke la aplicacion a crackear, y al
 ejecutarse este ejecuta el proceso, y hace los cambios necesarios.

 En concreto en script ke propuso [yAtEs] fue el siguiente:

 ;****************************************
 ;MuseArc Script by [yAtEs]

 T=1000:                  ; TRY 1000 TIMES (thats 4096 in decimal :)
 F=musearc.exe:           ; exe name
 P=40D24F/7C/EB:          ; change 7C (JL) to EB (JMP)
 $
 ;****************************************

 Solo una nota mas a cerca de este script. Bien, la primera linea significa,
 como ahi pone, ke se hagan un total de 4096 intentos. Estos son los 
 numero de intentos ke tiene para encontrar los bytes a parchear antes de
 ke el programa caske.. el error ke daria es, si no me ekivoco, el de numero
 de version no valido. Ademas de esto, esa linea se podria suprimir puesto
 ke por defecto, si no se especifica ningun valor, se pone a 8000(hex). 
 yo en casa tengo en concreto la version:
                     r!sc's process patcher v1.5.1
                     r!sc  --  http://beam.to/risc
 Es una herramienta util, os la aconsejo a todos.




3.- EL PROBLEMA DEL PERIODO DE PRUEBA.

Pues vamos a probar nuestro nuevo mp3 player y vemos ke ni de coa, no nos
deja, en lugar de salir alguna bonita ventana donde elegir la cancion ke
deseamos escuchar en este momento, aparece una odiosa ventana ke tiene por
titulo museArc BETA y ke nos notifica ke el periodo de prueba del ke
disponiamos para usar este programa ha finalizado en noviembre de 1997.
Tambien nos dan tanto la pagina web como una direccion de correo electronico
para contactar en caso de kerer conseguir informacion. Tenemos la opcion de
pulsar el boton acepatar en esa ventana, lo kual lleva a la finalizacion del
programa... Asi pues, pasaremos a buscar alguna solucion a este pekeo
contratiempo...



 3.1.- PRIMER INTENTO FALLIDO.
 Por el momento, vamos a comenzar trabajando con el SoftICE, que es un gran
 debugger. Yo, como lo uso bastante, siempre lo tengo funcionando, aunke lo
 normal es tenerlo solo cuando se necesita... el SoftIce (SICE en lo
 sucesivo)tiene ke ser cargado antes ke el windows,asi ke este se carga con
 una linea en el autoexec.bat... linea ke podeis comentar cuando no lo
 necesiteis...
 La ventana a la que antes he hecho referencia tenia toda la pinta de ser una
 ventana del tipo MessageBoxA, asi que vamos a poner un punto de ruptura en
 esa funcion. Para ello, primero se arranca el symbol loader, una pequea
 utilidad que viene junto con el SICE, y en el menu file se escoje load
 exports, y seguidamente se elije  la libreria user32.dll, que es la que
 contiene la funcion MessageBoxA. Esto se hace para ke despues podamos poner
 puntos de ruptura en funciones de esa libreria. En el mismo menu, con open
 module cargamos la aplicacion a debuggear, asi ke elegimos el archivo
 MuseArc.exe. Le damos para continuar al pekeo boton con un dibujo de ruedas
 dentadas en la esquina superior izquierda del loader. Ahora nos aparece una
 ventana de error,debido a ke no se encuentra informacion sobre depuracion...
 Le damos al si...  y salta la ventana del SICE, que ha parado en la
 primera instruccion del programa. Es una ventana un poco cutre, en modo
 texto y tal... pero desde ella se pueden hacer maravillas... :)
 Ponemos el punto de ruptura en la funcion que antes comente
 (con bpx messageboxa ) y le damos a CONTROL+D(Esta combinacion de teclas
 conmuta entre windows y el debugger), y vuelve a saltar el debugger, ahora
 en la primera instruccion de esa rutina. Pulsamos F12 (Ejecutar la rutina
 entera y parar en la siguiente instruccion), y el programa se sigue
 ejecutando, aparece la ventana del MuseArc ke da tanta tirria...le damos al
 boton, y volvemos al SICE. Komo nos indica la linea inferior de la ventana
 de codigo, estamos en el musearc, en la seccion .text.. este es el nombre
 comun para la seccion de codigo: MUSEARC!.text+00....),y puedo ver:

	:
 015F:00438C3B           CALL    [USER32!MessageBoxA]
 015F:00438C41           POP     EDI              <- Aparecemos aqui
 015F:00438C42           POP     ESI
 015F:00438C43           RET     000C
	:
	:
 Hechando un vistazo por encima al codigo que hay por aqui no veo nada digno
 de mencion, asi ke de nuevo F12, y llegamos hasta:
	:
 015F:0040D20B           CALL    00438C0C
 015F:0040D210           PUSH    FF               <- Aparecemos aqui
        :
        :
 Le hecho un vistazo tambien a esto pero sigo sin ver nada intersante, asi ke
 F12 again.... y el programa termina su ejecucion... Asi ke habra ke buscar
 otro camino...



 3.2.- GetSystemTime(), ENCONTRAMOS EL SALTO CONDICIONAL.

 En algun momento, el programa tendra que mirar a que dia estamos, para
 decidir si el plazo a concluido o no... eso lo hara probablemente con una
 llamada a la funcion GetSystemTime(), que se encuentra en la libreria
 kernel32.dll. En concreto esta funcion esta definida como sigue:

 VOID GetSystemTime{
        LPSYSTEMTIME lpSystemTime
                   };

 La estructura ke se le pasa como parametro es rellenada con la fecha y hora
 del sistema. Esa estructura esta definida como sigue:

 typedef struct _SYSTEMTIME {
        WORD wYear;
        WORD wMonth;
        WORD wDayOfWeek;
        WORD wDay;
        WORD wHour;
        WORD wMinute;
        WORD wSecond;
        WORD wMilliseconds;
  } SYSTEMTIME;


 Asi que deshabilitamos el punto de ruptura que tenia ( bd 0) y pongemos otro
 en GetSystemTime. A continuacion vuelvemos a ejecutar el mouseArc. El
 SICE para por primera vez, y despues de hechar un vistazo por ahi,hacemos ke
 se siga ejecutando, a ver que pasa... El programa para por segunda vez, y...
 ahora parece ke si dimos en el clavo :) llegamos al siguiente codigo:

	:
 015F:0040D22B           CALL    [KERNEL32!GetSystemTime]
 015F:0040D231           MOV     EAX,[ESP+04]   <- Tamos aki
 015F:0040D235           XOR     ECX,ECX
 015F:0040D237           MOV     CX,[ESP+06]
 015F:0040D23C           AND     EAX,0000FFFF
 015F:0040D241           LEA     EDX,[EAX*2+EAX]
 015F:0040D244           LEA     EAX,[EDX*4+ECX]
 015F:0040D247           SHL     EAX,04
 015F:0040D24A           CMP     EAX,0005DAA0
 015F:0040D24F           JL      0040D258
 015F:0040D251           MOV     ECX,ESI
 015F:0040D253           CALL    0040D1F0
	:
	:

 Y si ahora nos fijamos un poco, vemos que ese ultimo call de la lista nos
 lleva justo delante de la llamada ke luego desenvoca en el MessageBoxA().
 Por tanto la unica opcion ke tenemos es ke se ejecute ese salto condicional.
 Hagamos la prueba... Pulsando F10 (F10 es para ir instruccion a instruccion,
 pero sin entrar en las funciones) varias veces llegamos hasta el salto
 condicional. Cuando estamos sobre el, al lado derecho de la linea aparece un
 mensaje diciendonos que este no se va a ejecutar. Para variar esto podemos,
 por ejemplo, cambiar el valor del flag de signo, que ahora es 0. Esto lo
 hacemos con la orden: "r fl +s". A continuacion deshabilitaremos todos los
 puntos de ruptura ( bd *) y pulsaremos CONTROL+D, para salir de debugger....
 y ahora el programa funciona bien :).



 3.3.- PARCHEAMOS EL EJECUTABLE Y...PLOF!

 Bueno, pues ya hemos encontrado el punto k estabamos buscando. Tenemos un
 salto condicional despues de una llamada a la funcion GetSystemTime, y
 tenemos ke si ese salto condicional no se ejecuta indica k el periodo de
 prueba ha expirado. Por lo tanto la solucion mas obvia es la de cambiar el
 salto condicional por un salto incondicional con ayuda de un editor
 hexadecimal.
 Ahora mismo,tal como tengo configurado el SICE, no estoy viendo el codigo
 de las instrucciones ( code off), pero necesito verlo, por lo ke introduzco
 "code on" y copio una cadena de codigo ke kontenga el salto condicional, y
 ke sea lo suficientemente grande como para ke vaya a ser una cadena unica
 cuando la buske dentro del ejecutable. La cadena sera la siguiente:
                 "3D A0 DA 05 00 7C 07 8B CE"
 Ahora bien, dentro de esa cadena el salto condicional lo representa el
 "7C 07", y para ke esto sea un salto incondiconal ( o sea, ke salte siempre
 ke es lo ke keremos) solo hay ke cambiar "7C 07" por "EB 07". Pues nada,
 cogemos nuestro editor hexadecimal favorito y hacemos el cambio, habiendo
 hecho antes, por supuesto una copia de seguridad del ejecutable
 ( museArc.exx en mi caso), por si metemos la pata, k siempre es posible :)

 Ahora probamos a ejecutar el programa parcheado, y nos sale un error de la
 oxtia :(... De hecho, lo ke ha pasado es ke me a saltado el SICE y he
 podido leer en una linea azul txungo lo siguiente:

 Break due to Page fault (0Eh) fault=0004

 Esto ha pasado porke se ha producido un fallo de pagina, y normalmente por
 defecto el SICE salta ante cualkier fallo de pagina. Esto lo podemos
 deshabilitar con "faults off". Una vez hecho esto nos sale la ventanita
 diciendonos ke el programa ha efectuado una operacion no admitida y ke sera
 interrumpido. :(




4.- EL CHECKSUM. LA MODIFICACION DEL EJECUTABLE HA SIDO DETECTADA.



Bueno, y ke koo pasa aki??? Pues la respuesta parece bastante clara. O
metimos la pata hasta el fondo y no nos dimos cuenta, o el programa checkea
que el ejecutable ( o al menos una parte de el) no se haya modificado.
Como no creo ke me haya ekivocado :) sera la segunda opcion... Este progama
tendra por algun lado lo ke se denomina un checksum. Esto es ni mas ni menos
ke una rutina ke comprueba la integridad del archivo. No kiero en entrar
en detalles de como lo hace tampoco. Hay muchas formas de hacerlo, y pueden
haber usado desde una simple suma (XOR) de los bytes del archivo hasta la
cosa mas complicada y enrevesada ke os podais imaginar. El caso es ke hay
una rutina ke hace algo tal ke asi:

                      rutina checksum
                       Miro mi ejecutable;
                       si (ejecutable ha sido modificado) entonces
                         te doy por el culo;
                       fin_si;
                      fin_rutina

Y voy a hacer algun comentario mas al respecto. Aunke en este caso la rutina
esta en el propio ejecutable, no tiene porke ser asi. Podriamos tener la
rutina ke chekea el ejecutable en una libreria .dll... y es mas..podriamos
tener ademas de eso, despues una rutina ke chekea la libreria en el
ejecutable, por ejemplo (Si mal no recuerdo...espero no ekivocarme, esto pasa
por ejemplo en el HotMetal Pro 6.0)....
Para asegurarnos de ke nos hemos encontrado con un checksum, el metodo mas
utilizado es el de hacer modificaciones dentro del ejecutable de forma ke
estas no cambien el funcionamiento normal del programa. Me refiero por
ejemplo a algun cambio en la cadena de texto de "This program cannot be
run...", o cambiar "xor eax,eax" por "sub eax,eax" (las dos ponen eax igual a
0), o cosas por el estilo.
Si ante alguna de estas modificaciones el programa deja de funcionar podemos
asegurar de ke nos encontramos ante un checksum. De todas formas, en caso de
ke el programa siga funcionando correctamente, no podemos asegurar nada.

Y volviendo al tema k nos ocupa, nosotros estamos en la parte ke nos da por
culo. Asi ke habra ke buscar soluciones para esto.




 4.1.- SOLUCION 1... EL LOADER.

 Pues esta es la primera solucion ke se me ocurre. Un loader es un pekeo
 programa ke lanza nuestra victima y hace en ella todas las modificaciones
 necesarias para ke todo funcione correctamente.... osea ke aki lo ke se
 trataria es de hacer un programa ke de alguna manera automatice el proceso
 ke hemos llevado a cabo con el debugger. Como de esta manera no
 modificariamos el ejecutable no nos tendremos ke preocupar del checksum.
 Esta es tambien la solucion adoptada en el T.U.G., solo ke en este caso se
 ayudaban de un programa, mientras ke aki explicaremos como hacer el loader
 nosotros mismos, y en ensamblador.
 En concreto lo ke haria nuestro programa no seria esperar a ke la ejecucion
 llegase a ese salto y seguidamente hacer la modificacion. Sabemos donde se
 encuentra el salto, y sabemos komo lo tenemos ke parchear. Asi pues, lo ke
 haremos es parchear el salto al inicio del programa i despues dejarlo
 ejecutarse libremente.

 Entonces, deciamos ke ibamos a construir un  programa  ke deberia hacer lo
 siguiente:

        1.- Crear un nuevo proceso, el museArc, pero no dejar ke se ejecute,
        o dicho con otras palabras, krear el proceso como suspendido.

        2.- Acceder a la posicion de memoria en la que esta el salto
        condicional y cambiarlo  por un salto incondicional.

        3.-Permitir ke kontinue la ejecucion de dicho proceso.

        4.- Terminar.

 Una vez ke hagamos este programa,cada vez k keramos usar el museArc lo unico
 ke tenemos ke hacer es ejecutarlo.


  4.1.1.- FUNCIONES KE ES NECESARIO CONOCER.

   
  Para llevar a cabo las tareas ke he expuesto arriba es necesario conocer
  una serie de funciones de la api de windows, ke voy a a pasar a comentar a
  continuacion. Esto es mas o menos lo k dice de ellas el archivo Win32.hlp:
  Win32 Programmers Reference, archivo de ayuda ke siempre es recomendable
  tener :) todas los comentarios k hago de funciones de la api de windows
  estan sacados de este archivo.


   4.1.1.1.- CREATEPROCESS();

   BOOL CreateProcess(

    LPCTSTR lpApplicationName,	
    LPTSTR lpCommandLine,	
    LPSECURITY_ATTRIBUTES lpProcessAttributes,
    LPSECURITY_ATTRIBUTES lpThreadAttributes,
    BOOL bInheritHandles, 
    DWORD dwCreationFlag,
    LPVOID lpEnvironment, 
    LPCTSTR lpCurrentDirectory,
    LPSTARTUPINFO lpStartupInfo,
    LPPROCESS_INFORMATION lpProcessInformation 
   );

   lpApplicationName: es un puntero a una cadena terminada en null, que
   especifica el modulo que se ha de ejecutar. Esta cadena puede ser NULL, y
   ser el nombre del mudulo la primera cadena delimitada por espacios en
   blanco dentro del lpCommandLine.

   lpCommandLine: puntero terminado en NULL, que apunta a la linea de comando
   a ejecutar. Este argumento puede ser NULL, y especificar el comando a
   ejecutar en lpApplicationName. Si lpApplicationName es NULL, el primer
   espacio en blanco delimita el nombre del comando. Si este nombre no tiene
   extension, se le aade ".exe", pero sei el nombre del fichero termina en
   punto, sin extension, o el nombre del fichero contiene el path, el ".exe"
   no es aadido. Si el nombre del fichero no contiene el path, windows busca
   el ejecutable siguiendo la secuencia:
	1- El directorio desde donde la aplicacion es cargada
	2- El directorio actual del proceso padre
	3- El directorio system de windows
	4- En los directorios listados el el PATH.
   Y despues de esto, decir ke lo recomendado es dejar siempre 
   lpApplicationName a NULL, y usar lpCommandLine.

   lpProcessAttributes: puntero a una estructura SECURITY_ATRIBUTES, la cual
   expongo un poco mas abajo. A decir verdad, todo lo ke puedo decir aki ya
   lo digo en el argumento lpThreadAttributes, asi ke tira millas...

   lpThreadAttributes: puntero a la estructura SECURITY_ATRIBUTES, que
   determina si el handle retornado puede ser o no heredado por el proceso
   hijo. Si lpThradAttributes el NULL, el handle no puede ser heredado.

   typedef struct _SECURITY_ATTRIBUTES {
    DWORD  nLength;              // Tamao de la estructura
    LPVOID lpSecurityDescriptor; 
    BOOL   bInheritHandle; 
   } SECURITY_ATTRIBUTES; 

   binheritHandles: indica si el nuevo proceso hereda handles del proceso que
   lo llama. Si es TRUE, cada heredable handle del proceso que lo llama es
   heredado por el nuevo proceso.
   
   dwCreationFlags: es una cualquier combinacion de las siguietes flags:

    CREATE_DEFAULT_ERROR_MODE: El nuevo proceso no hereda el error mode del
    proceso que realiza la llamada. CreateProcess le da al nuevo proceso el
    error mode por defecto. Una aplicacion actualiza el error mode por
    defecto llamando a SetErrorMode.

    CREATE_NEW_CONSOLE: El proceso tiene una nueva consola en vez de heredar
    la del padre. Este flag no puede ser usado con el de DEATACHED_PROCESS.

    CREATE_NEW_PROCESS_GROUP: El nuevo proceso es el proceso raiz de un nuevo
    grupo de procesos. Este grupo incluye todos los procesos que son
    descendientes de el.

    CREATE_SUSPENDED: Pues eso mismo, el nuevo proceso es creado en estado de
    suspendido, y no se ejecutara hasta que no sea llamada la funcion
    ResumeThread. Esta es en concreto la flag ke nos interesa a nosotros :)

    CREATE_UNICODE_ENVIRONMENT: Indica que el bloque al que apunta
    lpEnvironment usa caracteres unicode
    
    DEBUG_PROCESS: El proceso que hace la llamada es tratado como un debugger,
    y el nuevo proceso es un proceso que esta siendo depurado.
   
    DEBUG_ONLY_THIS_PROCESS: Si este flag no esta activo y el proceso que
    realiza la llamada esta siendo depurado, el nuevo proceso se convierte en
    otro proceso siendo depurado por ese mismo debugger.

    DEATACHED_PROCESS: Este flag es para procesos de consola. Si se  activa,
    el nuevo proceso no tiene acceso a la consola del proceso padre. El nuevo
    proceso puede crear una nueva consola llamando a AllocConsole. Este
    proceso no puede ser usado junto con el flag CREATE_NEW_CONSOLE

   Este parametro tambien controla las prioridades del nuevo proceso. Si
   ninguna de estas flags es especificada, por defecto se usa
   NORMAL_PRIORITY_CLASS, a no ser que la prioridad del proceso creador sea
   IDLE_PRIORITY_CLASS, en cuyo caso el proceso hijo tendra esa misma
   prioridad. Las siguientes flags pueden ser especificadas:
   
    HIGH_PRIORITY_CLASS: Para procesos en los que el tiempo de respuesta es
    critico.
    IDLE_PRIORITY_CLASS: Estos procesos se ejecutan unciamente cuando el
    sistema no esta haciendo nada.
    NORMAL_PRIORITY_CLASS: El proceso es un proceso normal.
    REALTIME_PRIORITY_PROCESS: Es el nivel mas alto de prioridad que se puede
    dar a un proceso. Este proceso se encotraria por encima de procesos de SO
    a nivel de prioridad, con lo que si se ejecutase durante un cieto tiempo
    podria dar la sensacion de que el ordenador se ha colgado.

   lpEnviroment: este parametro apunta al bloque de entorno para este proceso.
   Si este es NULL, se coge el entorno del proceso que realizo la llamada. El
   bloque de entorno consiste en un bloque terminado en NULL de cadenas de
   caracteres tambien terminadas en NULL. Cada una de estas cadenas tienen la
   forma "nombre=valor". El caracter '=' es usado como separador, por lo que
   no puede ser incluido en el nombre de ninguna variable de entorno. El
   bloque de entorno puede conterner caracteres ANSI o UNICODE. Esto se
   indica en dwCreationFlags, con CREATE_UNICODE_ENVIROMENT.
   
   lpCurrentDirectory: puntero, NULL-terminado que especifica la unidad y el
   directorio para el proceso hijo. Si este parametro es NULL, se cogen los
   valores del proceso padre.
 
   lpStartupInfo: puntero a una estructura STARTUPINFO, que especifica como
   debe aparecer la ventana del nuevo proceso
 
   typedef struct _STARTUPINFO {   
    DWORD   cb; 
    LPTSTR  lpReserved; 
    LPTSTR  lpDesktop; 
    LPTSTR  lpTitle; 
    DWORD   dwX; 
    DWORD   dwY; 
    DWORD   dwXSize; 
    DWORD   dwYSize; 
    DWORD   dwXCountChars; 
    DWORD   dwYCountChars; 
    DWORD   dwFillAttribute; 
    DWORD   dwFlags; 
    WORD    wShowWindow; 
    WORD    cbReserved2; 
    LPBYTE  lpReserved2; 
    HANDLE  hStdInput; 
    HANDLE  hStdOutput; 
    HANDLE  hStdError; 

   } STARTUPINFO, *LPSTARTUPINFO; 

   A pesar de su tamao, la mayoria de los campos son ignorados a no ser ke
   se especifike en dwFlags, asi pues, poniendo este campo a 0, solo hay k
   preocuparse de los campos ke hay ke rellenar obligatoriamente con ciertos
   valores determinados. Estos son:
    cb: Con el tamao total de la estructura.
    lpReserverd: con NULL
    lpDesktop: con NULL
    lpTitle: con NULL
    cbReserved2: con 0
    lpReserved2: con NULL
    
   lpProcessInformation: puntero a la estructura PROCESS_INFORMATION que
   recibe informacon acerca del nuevo proceso.

   typedef struct _PROCESS_INFORMATION {
    HANDLE hProcess; 
    HANDLE hThread; 
    DWORD dwProcessId; 
    DWORD dwThreadId; 
   } PROCESS_INFORMATION; 


   En caunto al valor de retorno de esta funcion, si la funcion falla, el
   valor que retorno es 0. Para conseguir mas informacion, habria que llamar
   a GetLastError. En caso de que la funcion se ejecute satisfactoriamente,
   el valor de retorno sera distinto de 0.
   


   4.1.1.2.- WRITEPROCESSMEMORY();


   BOOL WriteProcessMemory(
    HANDLE hProcess,
    LPVOID lpBaseAddress,
    LPVOID lpBuffer,
    DWORD nSize,
    LPDWORD, lpNumberOfBytesWritten
   };

   hProcess: Identifica un handle abierto a un proceso cuya memoria va a ser
   escrita. El handle debe tener los accesos PROCESS_VM_WRITE y
   PROCESS_VM_OPERATION al proceso.

   lpBaseAddress: Apuntara a la direccion donde queremos escribir.

   lpBuffer: Puntero al buffer que contiene los datos que van a ser escritos.

   nSize: Especifica el nuemero de bytes que queremos escribir.

   lpNumberOfBytesWritten:Apunta al numero actual de bytes transerfidos a ese
   proceso en concreto. Este parametro puede ser ignorado si hacemos este
   puntero igual a NULL.

   En caso de que la ejecucion de esta funcion sea satisfactoria devolvera un
   numero distinto de 0. En el caso de que algo haya ido mal, la funcion
   devolvera 0 y se podra conseguir mas informacion llamando a GetLastError().



   4.1.1.3.- FLUSHINTRUCTIONCACHE();


   BOOL FlushInstructionCache(
    HANDLE hProcess,
    LPCVOID lpBaseAddress,
    DWORD dwSize
   );

   hProcess: Handle del proceso cuya cache queremos llenar.

   lpBaseAddress: Puntero que apunta a la region de memoria.

   dwSize: Tamao de dicha region.

   Esta funcion lo que hace es llenar la cache para el proceso que se
   especifica. La funcion devuelve 0 solo en el caso de que se haya producido
   algun error. Se puede obterner informacion extra con GetLastError();


   4.1.1.4.- RESUMETHREAD();


   DWORD ResumeThread(
    HANDLE hThread
   );

   hThead: Identifica el proceso que deseamos que se siga ejecutando.

   Esta funcion decrementa la cuenta de suspenso del proceso. Cuando esta
   cuenta llega a 0, la ejecucion del proceso continua. Por tanto, un valor 0
   en esa cuenta significa que el proceso no se encuentra actualmente
   suspendido.

   En caso de que la funcion se ejecute sin ningun problema devuelve el valor
   previo de la cuenta, y devolvera -1 en caso de haberse producion algun
   error.



  4.1.2.- EL CODIGO DE NUESTRO LOADER.

  Aki voy a comenzar poniendo el codigo del loader, i despues abajo lo
  comentare con algo de detalle.

  ----------------------el archivo muse.asm comienza aki------------------
  ;
  ; muse.asm
  ; Para el musearc.exe v ????
  ; marconi, diciembre del 2000
  ; inocram@yahoo.com
  ;
  ; 
  ; ml /c /coff muse.asm
  ; link /SUBSYSTEM:WINDOWS /LIBPATH=c:\masm32\lib muse.obj
  ; 

  .386
  .MODEL flat,STDCALL
  option casemap:none               ;diferenciar entre mays y mins
                                    ;equivalente a la opcion /Cp

  include c:\masm32\include\windows.inc               ;windows.inc de hutch
  include c:\masm32\include\kernel32.inc
  include c:\masm32\include\user32.inc                ;messagebox y demas
  includelib c:\masm32\lib\kernel32.lib
  includelib c:\masm32\lib\user32.lib
  
  .data
  error      db  "Error en la aplicacion...",0   ;titulo de la ventana de 
                                                                  ;error
  archivo    db  "musearc.exe",0                 ;Nombre del ejecutable
  rva        dd  0040D24Fh                       ;Relative Virtual Address
  data       db  0ebh                            ;datos a escribir                 
 
  .data?
  infoinicio STARTUPINFO <>
  procinfo   PROCESS_INFORMATION <>
  cad        dd  ?

  .code
  inicio:                                        ;Punto de entrada

  ;rellenamos los valores de la estructura procinfo...
  invoke GetStartupInfo,addr infoinicio
  
  ;creamos el proceso suspendido...
  invoke CreateProcess,NULL,addr archivo,NULL,NULL,FALSE,\
                     CREATE_SUSPENDED,NULL,NULL,addr infoinicio,\
                     addr procinfo          
  test   eax,eax                                   
  je     fallo
  
  ;escritura en memoria...
  invoke WriteProcessMemory,procinfo.hProcess,rva,addr data,1,NULL
  test eax,eax
  je fallo
  invoke FlushInstructionCache,procinfo.hProcess,rva,1
  test eax,eax
  je fallo

  ;Hacemos ke el proceso salga de su estado de suspendido...
  invoke ResumeThread,procinfo.hThread
  cmp eax,-1
  je fallo
  ;Todo fue bien, vamos a la salida...
  jmp salida                                
  

  ;Errores...
  fallo:
  invoke GetLastError
  invoke FormatMessage,FORMAT_MESSAGE_ALLOCATE_BUFFER + \
                      FORMAT_MESSAGE_FROM_SYSTEM,NULL,eax,0,addr cad,0\
                      ,NULL
  invoke MessageBox,0,cad,addr error,MB_OK+MB_ICONINFORMATION
  invoke LocalFree,cad
 

  ;salida del programa...
  salida:
  invoke ExitProcess,NULL
  end inicio
  ---------------------el archivo muse.asm termina aki---------------------

  Voy a comentar por encima lo ke hace este programa en cuestion.Ya he puesto
  al principio cuales serian las lineas para compilarlo y enlazarlo. Este
  codigo esta pensado para el masm :)...
  Por un lado hay k destacar ke aadi algo de codigo adicional ke se encarga
  de mostrar mensajes de error en caso de ke algunas de las llamadas no se
  ejecute satifactoriamente. Esta parte de codigo no la voy a comentar, pues
  kreo ke es bastante claro y ademas se escapa a los objetivos de este
  articulo.
  Lo primero ke hacemos es rellenar la estructura infoinicio, ke es del tipo
  STARTUPINFO. Necesitaremos esta estructura correctamente rellenada para
  despues poder llamar a la funcion CreateProcess. Ya comente antes k no son
  muchos los campos k hay k rellenar de esta estructura. De todas formas en
  vez de rellenar los campos lo ke hice fue hacer una llamada a la funcion
  GetStartupInfo, ke rellena esa estructura con los datos del programa ke la
  llamo. Seguidamente. Llamamos a CreateProcess para crear el proceso y le
  indicamos ke cree el proceso MuseArc.exe y lo ponga en estado suspendido.
  Seguidamente, accedemos a la memoria de ese proceso, con una llamada a la
  funcion WriteProcessMemory() y otra a la funcion FlushInstructionCache()
  para sobreescribir el salto condicional y reemplazarlo por un salto
  incondicional. Llamamos a ResumeThread() para ke el proceso se siga
  ejecutando, i finalizamos.

  Este programa es una chapucilla, como podeis ver. Hay cosas k se deberian
  hacer y sin embargo no se hacen, como por ejemplo leer primero el trozo de
  memoria ke se va a sobreescribir, para ver si estamos parcheando el lugar
  correcto (ReadProcessMemory()).... pero tampoco keria complicarlo mas...
  empece con la idea de hacer algo muy muy sencillo, y aun asi acabe metiendo
  codigo sin el cual el loader seguiria funcionando perfectamente.
  
  Si ahora metemos el ejecutable generado por este codigo fuente en el mismo
  directorio donde tenemos instalado el MuseArc, y seguidamente ejecutamos
  nuestro pekeo enjendro, veremos ke el MuseArc arranca sin ningun problema
  :)))))
  Les he mandado una copia del programa junto con el parche a algunos de mis
  amigos, y he tenido kejas, porke a pesar de ke el parche se salta la
  ventanita toca-cojones, despues, al intentar escuchar alguna cancioncilla
  el programa se va a tomar por culo.... le he estado dando bastantes vueltas
  buscando alguna relacion entre el parche y los fallos del programa pero no
  he visto nada... sinceramente creo ke lo ke pasa es ke el programa es una
  MIERDA... el fallo en cuestion solo lo da con algunos mp3... por eso no lo
  habia advertido al principio... de hecho a mi solo me dio problemas una de
  10 canciones ke probe, y siempre la misma... bueno, kizas si tenga algo ke
  ver y yo este obcecado y no lo vea (aunke no creo ;) jejeje en todo caso,
  avisados estais...




 4.2.- SOLUCION 2... INTRODUCIENDO CODIGO PROPIO EN UN EJECUTABLE.

 Bien, vamos con la segunda posible solucion... pero antes, recordar donde
 estabamos... Hasta el momento teniamos un MuseArc.exe parcheado, pero ke por
 culpa del parche acababa dando un error de fallo de pagina, y por otro lado
 teniamos una copia de seguridad del musearc.exe, que habia llamado
 musearc.exx
 Pues vamos a ello....
 Lo ke en este apartado haremos sera introducir codigo propio dentro del
 archivo ejecutable MuseArc.exe, como bien reza el titulo. Esta tecnica se
 puede usar para muchas mas cosas ke el cracking, si bien es para esto para
 lo ke lo vamos a usar aki. Tambien nos podriamos apoyar en esta tecnica para
 dotar a programas de nuevas capacidades, modificar el comportamiento, etc.
 No me enrollo mas....



  4.2.1.- BUSCANDO UN PUNTO DE ATAKE
  
  Sabemos ke el error lo da porke se da cuenta de ke el archivo musearc.exe
  ha cambiado, eso esta bastante claro. Y otra cosa ke esta bastante clara es
  ke para darse cuenta de ke ese archivo ha cambiado el programa debe hacer
  algunas cosillas tales como por ejemplo abrir el archivo musearc.exe. Este
  es un posible punto de atake para comenzar y a ver a donde llegamos. Para
  abrir un archivo habran usado alguna funcion de la api de windows, y si le
  hechamos un vistazo, podremos ver ke las funcion candidata para poner
  breakpoints es:

  HANDLE CreateFile(

    LPCTSTR lpFileName,	
    DWORD dwDesiredAccess,	
    DWORD dwShareMode,	
    LPSECURITY_ATTRIBUTES lpSecurityAttributes,
    DWORD dwCreationDistribution,	
    DWORD dwFlagsAndAttributes,
    HANDLE hTemplateFile
   );
  y voy a pasar a comentar los argumentos: 

  lpFileName: Puntero al nombre del archivo, terminando en nulo. (en realidad
  esta funcion no se restringe a archivos, sino ke tambien pueden ser
  directorios, pipes...). Se puede especificar el path tambien en este
  argumento. En realidad este es el unico parametro ke nos interesa, de todas
  formas voy a describir el resto brevemente...

  dwDesiredAccess: Tipo de acceso al objeto. Especifica si se va a abrir como
  solo lectura, lectura-escritura.....

  dwShareMode: Indica como se va a compartir el archivo. Es una combinacion
  de los valores FILE_SHARED_READ, FILE_SHARED_WRITE, FILE_SHARED_DELETE.. y
  en caso de ser 0, significa ke el objeto no sera compartido.

  lpSecurityAttributes: Puntero a una estrucutra SECURITY_ATTRIBUTES, ke
  especifica si el handle puede ser heredado... mirad el numero uno sobre el
  musearc para mas informacion.

  dwCreationDistribution: Especifica ke accion hacer en caso de ke el archivo
  exista(o no)...OPEN_ALWAYS,OPEN_EXISTING,CREATE_NEW, etc

  dwFlagsAndAttributes: Especifica atributos y flags para el archivo. 
  Atributos como archivo comprimido, de solo lectura... y flags indicando por
  ejemplo ke el archivo se abrira sin buffers intermedios, ke el archivo sera
  accedido de acuredo con POSIX, o cosas por el estilo

  En cuanto al valor devuelto por esta funcion, tenemos ke devuelve bien el
  handle, bien INVALID_HANDLE_VALUE, si la funcion falla.

  Bien, mas cosas ke saber... la funcion se llama createfile(), pero sabemos 
  ke esta funcion en realidad despues sera createfilea() o createfilew(), ke
  son sus versiones ascii (con la a) y unicode (con la w, w de word supongo).
  si en el softice pruebas a poner un punto de ruptura en createfile te dira
  ke no encuentra la funcion, aunke hayas cargado desde el symbol loader el 
  kernel32.dll con la opcion load exports. Esto es porke las funciones ke 
  realmente hay son esas otras dos, con la a y con la w. lo puedes ver 
  facilmente usando el el SICE el comando exp de exports. Puedes poner 
  "exp createfile" para ke te diga ke funciones tienes exportadas y comienzan
  de esa manera. La nuestra, es la version ascii, puesto ke las cadenas con
  las k trabajamos son cadenas ascii.

  Bien ahora ke ya conocemos la funcion... mas cosas ke tenemos ke mirar...
  bien... el archivo ke keremos ver cuando se abre es musearc.exe, y con el
  path completo es c:\program files\musearc\program\musearc.exe
  Asi ke la llamada a createfile() ke buscamos debe tener un puntero a 
  esta cadena en la pila. Asi ke vamos a ver. la ultima "e" del .exe del
  musearc esta en la posicion 43, o lo ke es lo mismo 02bh, y el puntero 
  esta en (esp+4), asi ke *(esp+4) apuntaria a c:\.... 
  bueno, si no entendisteis ke el puntero esta en esp+4...pues mirad la 
  cabecera de la funcion pork es directo.. doy por supuesto k sabes k los 
  argumentos de la funcion le son pasados en la pila, y ke la s y la p de
  esp significan stack pointer... tambien doy por supuesto k konoceis el
  orden en el k se le pasan los argumentos (convencion STDCALL). Si no sabeis
  todo esto pues deberiais!!! hay mucha informacion por ahi! 
  ASM forever!!! :P... bueno... sigo..... :)

  *(esp+4)+2b apuntaria a "e" o "E". Por lo tanto *(*(esp+4)+2b) deberia ser 
  igual a "e" o "E". Asi ke podriamos poner en el SICE el siguiente 
  punto de ruptura:

  bpx createfilea if byte (*(esp->4 + 2b))=='e' || byte (*(esp->4 + 2b))=='E'



  si os fijais en el punto de ruptura condicional podeis ver ke esp->4 es lo 
  mismo ke *(esp+4), y la palabra byte puesta delante indica ke la cantidad
  ke estamos direccionando en memoria es de tamao byte, pues por defecto
  cogeria dword, y entonces la cadena devuelta podria ser algo como "XX0E"
  donde las X son valores a priori no conocidos. Osea, en otras palabras eso
  es un casting. Ya sabeis (o deberiais) ke la cadena ke koje es "XX0E" y no
  "E0XX" debido a la endianity.El operador == es el operador de comparacion y
  el operador || es la suma logica(OR). 
  Si hacemos la prueba.. cogemos el loader, cargamos la aplicacion, la
  ejecutamos y cuando estamos en el punto de entrada ponemos el bpx y dejamos
  ke se siga ejecutando.... al momento la ventana del SICE vuelve a emerger
  como resultado del bpx... ponemos "d esp->4" para ver los datos, 

  0030:0044F350  C:\PROGRAM.......

  vamos a la ventana de datos ( si no la tienes visible, se hace con wd, y
  despues vuelve a introducir el d esp->4 para visualizar esa cadena en la
  ventana, y tambien recomiendo introducir db para ver en esa ventana los
  datos agrupados en bytes) y cambiamos la ultima "E" por una "X". A
  continuacion pulsamos F12 para saber desde donde fue llamada la funcion, y
  vemos....

  0167:004276A8   MOV     ECX,DWORD PTR[ESP+40]
  0167:004276AC   PUSH    EDX
  0167:004276AD   PUSH    EAX
  0167:004276AE   MOV     EBP,DWORD PTR[00465904]
  0167:004276B4   PUSH    ECX
  0167:004276B5   CALL    EBP
  0167:004276B7   CMP     EAX,-1            <- aparecemos en esta linea
  0167:004276BA   MOV     EBP,EAX

  Asi ya sabemos donde se efectuo esa llamada.

  Y ahora dejamos ke el programa siga ejecutandose...
  Y todo ha ido como la seda...el programa ha arrancado sin ningun problema...

  Ademas el bpx solo salta una vez, con lo ke la comprobacion de esa letra es 
  suficiente para discriminar cuando la llamada a esa funcion se hace para
  abrir el musearc.exe. Con esto kiero decir ke solo vamos a tener k parchar
  esa llamada aunk la funcion createfilea() se llame desde mas sitios.
  Eliminamos el punto de ruptura y nos tomamos un vodka :)



  4.2.2.- HACIENDOLO A MANO.

  Cual es nuestro objetivo ahora??....pues hacer las modificaciones
  necesarias para ke cuando se realice esa llamada (call ebp) sea el archivo
  musearc.exx y no el musearc.exe el k habra....
  Fijemonos bien, ke ecx esta apuntando a el nombre del archivo ke va a ser
  abierto, puesto ke es su valor el ke se empuja a la pila justo antes de la
  llamada a la funcion. La modificacion k vamos a hacer es la siguiente...
  escribiremos un trozo de codigo ke kompruebe si ecx apunta a
  c:\....\musearc.exe, y si es asi, modificaremos esa cadena para ke sea
  c:\.....\musearc.exx.
  Despues vamos a hacer otras dos cosas mas: por un lado introducir nuestro
  trozo de codigo en el programa, y por otro modificar ese cacho de codigo
  de ahi arriba de alguna manera para ke antes de ke se ejecute el call ebp,
  se ejecute nuestro trozo :) facil verdad?? :) 

  Pues para hacer esto ya existen varias herramientas por ahi, como el
  code snippet creator, de iczelion. Yo por ejemplo, tengo la version 1.05... pero tambien 
  podriamos hacerlo perfectamente sin utilizar herramienta alguna.

  Comenzare por explicar como vamos a hacer para dar el control a nuestra
  rutina... supongamos por un momento ke ya hemos introducido nuestro cacho
  de codigo dentro del ejecutable, entonces este cacho de codigo tendra una
  direccion virtual, por ejemplo 00365485. Una forma facil de saltar hasta
  ese punto seria pushear ese valor dentro de la pila y despues hacer un
  ret... de hecho esta es la tecnica ke utiliza el code snippet... haciendo
  eso tendriamos lo siguiente:

   
  6885543600      push 00365485
  c3              ret

  Asi ke ahora contamos es espacio ke okupan esas dos instrucciones, y vemos
  ke ocupan 6 bytes. Si ahora miramos el trozo de codigo vemos esta
  instruccion:

  0167:004276AE   MOV     EBP,DWORD PTR[00465904]

  ke kasualmente ocupa 6 bytes tambien (8B2D04594600)
  Asi k lo ideal seria cambiar esta instruccion por nuestras dos nuevas
  instrucciones.

  Por otro lado tenemos k introducir nuestro nuevo codigo dentro del
  ejecutable. Lo primeros ke se nos ocurre es buscar espacio sin utilizar
  dentro de alguna de las secciones del ejecutable y meterlo ahi, ademas asi
  no aumentariamos el tamao del ejecutable. Asi k abrimos el archivo
  ejecutable con un editor hexadecimal, en mi caso el UltraEdit, y buscamos
  una zona llena d 0's. Encontramos una en el desplazamiento 03de8ch. 
  A partir de este deplazamiento, tenemos k kalcular la VA (Virtual address,
  direccion virtual) Para ello nos ayudaremos de un editor de PE. Yo utilizo
  siempre el Procdump, de G-RoM, Lorian y Stone. No solo vamos a usar este
  editor para calcular la VA de ese punto, puesto k mas adelante utilizaremos
  tambien la opcion ke nos permite salvar secciones de un PE a un archivo en
  disco. Pero antes d nada, el rollo teorico....
  El archivo k estamos estudiando es un archivo de formato PE (Portable
  Executable). Este es el formato de archivo ejecutable nativo de Win32.
  El 99% de los archivos ejecutables .EXE y librerias dinamicas .DLL siguen
  este formato, que se deriva del sistema d archivos UNIX COFF (COFF= commnon
  object file format)... El caso es k en la estructura de estos archivos nos
  encontramos con multiples cabeceras en las k encontramos la info suficiente
  entre otras cosas para conseguir averiguar esa direccion virtual k
  necesitamos.... Y para acceder a esos valores nos vamos a ayudar del
  procdump.
  En concreto, los campos k necesitamos son los siguientes: Por un lado el
  valor del campo IMAGE BASE, que nos da la direccion virtual relativa de la
  base del archivo. Ademas d este valor, necestiamos acceder a cierta info
  sobre las secciones del archivo, valores k se guardan dentro de las tablas
  de las secciones.Aqui podemos encontrar datos como el nombre de la seccion,
  sus caracteristicas... etc.
  En concreto nosotros buscamos los siguientes datos:

  RAW SICE: Es el tamao de la seccion, valor ke el procdump calcula a partir
  d datos k aki encuentra (SizeofRawData)

  RAW OFFSET: Desplazamiento dentro del archivo del cuerpo de la seccion en
  cuestion.

  VIRTUAL OFFSET: Este es el desplazamiento virtual, respecto a BASE IMAGE.


  Con los campos RAW SICE y RAW OFFSET podemos calcular los desplazamientos
  del inicio i del final de las diferentes secciones dentro del archivo, asi
  podremos saber en ke seccion se encuentra el desplazamiento k hemos
  escogido. Una vez tengamos la seccion, si a nuestro desplazamiento le
  restamos el RAW OFFSET d la seccion en la k se encuentra tendremos el
  offset de nuestro punto, ahora respecto al inicio de la seccion en la k se
  encuentra. IMAGE BASE + VIRTUAL OFFSET es la direccion virtual del inicio d
  la seccion, por tanto si ahora sumamos esto al valor obtenido, lo k
  tendremos sera la direccion virtual k estabamos buscando.
  y ya ta :)))))))))

  Pues eso, arrancamos el procdump. Le damos al boton PE Editor, i elegimos
  el musearc.
  Leemos:

  Image Base: 00400000
  Ahora le damos al boton sections:
  Podemos ver ke tiene 6 secciones...

  Nuestro desplazamiento era 03de8Ch, i mirando la tabla podemos ver k se
  encuentra en la seccion .text. Si ahora hacemos los calculos:

  desp    -  Raw Offset     =Desplazamiento respecto el inicio de la seccion
  03de8ch -  00000400       =03D8Ach   

  Virtual Offset de la seccion + Image Base = VA Inicio seccion
  00001000                     + 00400000   = 00401000

  I sumando estos dos valores tenemos la direccion virtual k keriamos
  calcular

  Dir Virtual k buscamos: 00401000 + 03DA09=0043EA8C

  sigamos adelante :) Ahora lo ke debemos hacer es escribir un programa con
  el codigo k keremos introducir en el musearc :)


  --------------------- principio del archivo muse2.asm-------------------
  ;
  ; muse2.asm
  ; Para el musearc.exe v ???
  ; marconi, enero del 2001
  ; inocram@yahoo.com
  ;
  ; ml /c /coff muse2.asm
  ; link /SUBSYSTEM:WINDOWS /LIBPATH=c:\masm32\lib muse2.obj
  ;

  .386
  .MODEL flat,STDCALL
  option casemap:none 

  include c:\masm32\include\windows.inc 


  .code
  inicio:
  push    ecx                            ; guardamos ecx en la pila
  add     ecx,2bh                        ; Que apunte a la pos d la 'E'
  cmp     byte ptr [ecx],'E'             ; Es una 'E'????
  jne     fin                            ; Si no lo es nos vamos
  mov     byte ptr [ecx],'X'             ; Si lo es, ponemos la 'X'
  fin:
  pop     ecx                            ; Recuperamos ecx
  db      8bh, 2dh,4, 59h, 46h,0         ; Inst. k sobreescribimos
  push    004276B4h                      ; VA de retorno
  ret                                    ; Saltamos
  end inicio  

  ----------------------------fin del archivo muse2.asm----------------


  Una vez k hemos generado el ejecutable, lo k vamos a hacer es lo siguiente:
  sakaremos del ejecutable el cuerpo de la seccion .text, ke es exactamente
  el codigo ke hemos escrito. Esto lo hacemos otra vez con el procdump.
  Cogemos PE editor, elegimos el ejecutable k akabamos de crear, elegimos
  sections,  y elegimos la unica seccion k tiene, .text. Ahora dandole al
  boton dcho de raton aparece un menu en el ke podemos elegir save section
  to disk, le damos un nombre cualkiera, i la salvamos. Yo por ejemplo llame
  al nuevo archivo muse2text.dmp. Ahora con un editor hexadecimal abrimos el
  muse2text.dmp y el muse.exe e introducimos el contenido de muse2text.dmp en
  el musearc.exe, a partir del desplazamiento k habiamos calculado:

  Asi mismo, tambien parcheamos la posicion:

  0167:004276AE   MOV     EBP,DWORD PTR[00465904]

  con el codigo:
  688CEA4300      push 0043EA8C
  c3              ret

  Para ello buscaremos la cadena:

  52508B2D04594600

  y la sustituiremos por la cadena:

  5250688CEA4300C3

  Salvamos todos estos cambios, i ahora probamos a ver si el programa
  arranca...y vemos k lo hace sin ningun tipo d problema :)
  y nos tomamos otro vodka mas :))))



  4.2.3.- USANDO EL CODE SNIPPET CREATOR.

  Pues vamos a hablar de esta herramienta, creada por Iczelion. Este pekeo
  programa nos permite la posibilidad de escribir pekeos trozos de codigo
  o recortes de codigo como su nombre indica ( Sippet= recorte), e
  introducirlos dentro de un ejecutable. No me voy a parar a hacer una
  descripcion detallada de todas las posibilidades ke este programa ofrece,
  tan solo voy a explicar como hariamos para hacer con esta herramienta lo
  ke antes hicimos a mano.
  Tambien decir, ke este programa cuenta con un menu llamado PE Info, ke nos
  sirve para conseguir informacion ha cerca del ejecutable... en concreto
  toda la informacion sobre el MuseArc.exe ke hemos conseguido con ayuda del
  ProcDump, la podiamos haber obtenido con este programa.
  Recordar, una vez mas, ke estas modificaciones las haremos sobre el archivo
  MuseArc.exe en el ke ya habiamos parcheado una instruccion de salto, y en
  ese mismo directorio contamos con una copia de seguridad del MuseArc.exe
  original, al ke habiamos puesto el nombre MuseArc.exx.

   4.2.3.1.- DATOS KE NECESITAMOS.

   Pues vamos a ver primero los datos ke necesitamos saber, para despues
   poder comenzar a escribir nuestro recorte e insertarlo dentro del MuseArc.
   Estos datos ya los habiamos conseguido todos en el punto anterior asi ke
   solo vamos aki a hacer una pekea lista de lo ke habiams obtenido:

   Teniamos ke el offset donde vamos a introducir el recorte es el 03de8ch,
   y tambien habiamos calculado su VA, ke es uno de los valores ke vamos a
   necesitar, esta VA era en concreto:

                    VA Recorte: 0043EA8C

   Otro de los datos ke es necesario conocer es la VA desde donde keremos
   saltar a nuestro recorte... esta era, como habiamos visto:

                    VA desde donde saltar al recorte: 004276AE

   Y por ultimo, debemos saber tambien cual va a ser la VA de retorno, osea,
   a donde keremos k se salte despues de ke nuestro recorte se haya ejecutado
   y habiamos visto tambien ya esa direccion, ke era:

                    VA de retorno: 004276B4h

   Pues teniendo todos estos datos, lo unico ke hay ke hacer es ponerse ha
   escribir e introducir nuestro codio :)




   4.2.3.2.- ESCRIBIENDO E INTRODUCIENDO EL RECORTE.

   Pues vamos a ello.... abrimos el Code Snippet, y en el menu file escogemos
   new project. Le damos por nombre a nuestro proyecto MuseArc, y en como
   program escogemos el MuseArc.exe...podemos buscarlo por nuestro hdd usando
   el boton de browse. Una vez hehco esto solo tenemos ke darle al boton de
   "create" para krear el proyecto. Ahora contamos con una ventana en blanco
   encima de la cual pone Musearc, y debajo tenemos los botones de "Assemble"
   y "Exit". Hay ke tener en cuenta ke necesitamos configurar correctamente
   el programa para ke cuando le demos a "Assemble" el programa ensamble
   nuestro recorte sin problemas. La configuracion del esnamblador se
   encuentra en el menu "Action", opcion "Options".

   Y ahora a escribir nuestro recorte...


  -------------------------Principio del recorte----------------------------
  ;
  ; recorte para el MuseArc.exe
  ; Marconi, enero del 2001
  ;
  ; Para el Code Snippet Creator
  ;

  push    ecx                            ; guardamos ecx en la pila
  add     ecx,2bh                        ; Que apunte a la pos d la 'E'
  cmp     byte ptr [ecx],'E'             ; Es una 'E'????
  jne     fin                            ; Si no lo es nos vamos
  mov     byte ptr [ecx],'X'             ; Si lo es, ponemos la 'X'
  fin:
  pop     ecx                            ; Recuperamos ecx
  db      8bh, 2dh,4, 59h, 46h,0         ; Inst. k sobreescribimos
  push    004276B4h                      ; VA de retorno
  ret                                    ; Saltamos

  -------------------------Fin del recorte----------------------------------

  Como podeis ver, soy un vago del 15!... me limite a cortar el trozo de
  codigo ke habiamos hecho e introducido a mano...

  Ahora tenemos ke rellenar las opciones del proyecto, ke se encuentran en
  el menu actions. En esta ventana, tenemor ke introducir el VA del recorte
  (0043EA8C) donde nos lo pide ( Snippet VA),ademas debemos escoger dentro
  de patc options la opcion patch into existing section, ya ke keremos
  introducir nuestro codigo dentro de una seccion ke ya existe ( .text). Y
  en Address to Redirect Control to the snippet, tenemos ke escoger la opcion
  Redirect control from code section, y rellenar el campo virtual address con
  la VA correspondiente ( 004276AE).
  Si mirais atentamente esta ventana vemos ke tenemos opciones como por
  ejemplo devolver el control a la aplicacione en una VA, o restaurar las
  instrucciones ke han sido sobreescritas. Nosotros en este caso no
  utilizamos estas opciones puesto ke hemos reutilizado el codigo ke ya
  teniamos escrito antes :)
  
  Ya esta todo listo para darle a assemble...nos sale entonces una ventana
  con el nombre assembler output en la ke podemos ver ke ni el ensamblador ni
  el enlazador nos ha dado mensaje de error o aviso ninguno... el siguiente
  paso sera en el menu file, usar la opcion export. Nos sale una ventana
  en la ke podemos dar un nombre al archivo .bin ke se va a generar, i
  tambien podemos elegir la carpeta donde vamos a gurardar dicho archivo.
  Llamamos a dicho archivo por ejemplo MuseArc.bin, y lo guardamos en
  cualkier sitio. Nos aparece una pekea ventana indicando ke la operacion se
  ha llevado a cabo satisfactoriamente. Y ya estamos listo para hacer el
  siguiente y ultimo paso. En el menu action escogemos ahora la opcion Patch
  target file...y nos aparece otra ventana similar a la anterior indicando
  ke esta operacion tambien se llevo a cabo satisfactoriamente.... ahora
  podemos intentar ejecutar el MuseArc.exe, y vemos ke todo ha funcionado
  correctamente. :) Es el momento idoneo para tomarnos otro vodka :)))

  4.2.4.- Consideraciones finales.

  Aunke aki no hemos tenido la necesidad de trabajar con las caracteristicas
  de las secciones, normalmente si ke hay k hacerlo...por ejemplo, si en vez
  de modificar una cadena hubiesemos desde nuestro recorte modificar un trozo
  de codigo, habriamos tendio ke tocar las caracteristicas de esa seccion
  para poder hacerlo... no me kiero tampoco enrollar con esto...solo os
  dejo aki una tabla con las caracteristicas de las secciones...

        00000020  :  codigo
        00000040  :  datos inicializados
        00000080  :  datos sin inicializar
        04000000  :  seccion cacheable
        08000000  :  seccion paginable
        10000000  :  seccion compartida
        20000000  :  se puede ejecutar
        40000000  :  se puede leer
        80000000  :  se puede escribir

  pues ahi esta..por si lo necesitais algun dia xD




 Pues hasta aki esta segunda parte sobre el musearc.... este es un  ejemplo
 muy sencillo de como podemos introducir codigo propio dentro d un
 programa.




 4.3.- SOLUCION 3... MODIFICANDO LA RUTINA DE PROTECCION.


 Pues vamos a destripar un poco mas aun este programa :)...
 Al principio del todo, habiamos llegado a la conclusion de ke lo k habia k
 hacer para k el programa no se diese cuenta de ke la fecha paso era parchear
 un salto condicional...este salto se encontraba en concreto en la VA 40D24F:
 
 :0040D241 8D1440                  lea edx, dword ptr [eax+2*eax]
 :0040D244 8D0491                  lea eax, dword ptr [ecx+4*edx]
 :0040D247 C1E004                  shl eax, 04
 :0040D24A 3DA0DA0500              cmp eax, 0005DAA0
 :0040D24F 7C07                    jl 0040D258        <--- este salto.
 :0040D251 8BCE                    mov ecx, esi
 :0040D253 E898FFFFFF              call 0040D1F0

 Lo k haciamos, era cambiar ese salto condicional por un salto incondiconal. 

 El problema ke nos encontrabamos a continuacion, es k si intentabamos
 ejecutar el programa, nos saltaba es SICE con el menseaje siguiente:

 Break due to Page fault (0Eh) fault=0004

 Osea, peazo de fallo de pagina :(... este fallo se producia al intentar 
 ejecutar la instruccion situada en la VA 0040C773:


 :0040C769 03C1               add eax, ecx
 :0040C76B 3B0D90014600       cmp ecx, dword ptr [00460190]
 :0040C771 7418               je 0040C78B
 :0040C773 8A10               mov dl, byte ptr [eax]  <- aqui se jode todo
 :0040C775 8811               mov byte ptr [ecx], dl
 :0040C777 030D8C014600       add ecx, dword ptr [0046018C]
 :0040C77D 03058C014600       add eax, dword ptr [0046018C]
 :0040C783 3B0D90014600       cmp ecx, dword ptr [00460190]
 

 En el caso de ke programa hubiese funcionado bien, cabria dos posibilidades,
 o bien k esa instruccion se ejecutase una o varias veces y no hubiese
 generado un fallo de pagina,o bien ke nunca se hubiese llegado a ejecutar...
 como vamos a ver a continuacion es esta segunda posibilidad la k se da en
 este caso....

 Una forma sencilla para buscar un sitio donde parchear la rutina de
 proteccion es la siguiente: si no nos keremos parar a estudiar con
 detenimiento la rutina, podemos comparar la evolucion del programa
 "semiparcheado" con la evolucion del programa en el caso de k nunca lo
 hubiesemos tocado.... claro k aki nos topamos con un problema, i es ke si no
 tocamos el programa, una ventana nos dice ke hemos excedido el tiempo de
 pruebas, i no nos deja continuar. En caso de ke la comprobacion de la
 integridad del ejecutable se efectuase despues de la comprobacion del limite
 de tiempo, no podriamos comparar una mierda...
 y aki es donde hacemos lo k a todo el mundo se le ha ocurrido ya en la
 primera linea de la primera de las partes... y es retrasar el reloj del
 sistema.... el programa no se cosca i arranka sin ningun problema....
 y ahora dira alguno... me cago en la puta!!!! tanto rollo para k solo haya k
 retrasar el reloj del sistema!!!!!!!! me cago en tu p....hijo d p...te voy a
 m.... ..puto gordo g...  xDDDDDD jajajajjajajaj...posi :)
 Pero no nos desviemos del tema i vamos a lo k nos okupa. Tenemos una copia
 sin modificar del musearc original, i hemos atrasado el reloj del sistema.
 He desensamblado el ejecutable, i resulta k la instruccion donde la copia
 modificada se jode esta en una funcion k empieza en la VA 

 * Referenced by a CALL at Addresses:
 |:0040B092   , :0040B831   , :0040C74B   , :00410A69   , :00411E04   
 |
 :0040C700 64A100000000            mov eax, dword ptr fs:[00000000]
 :0040C706 55                      push ebp
 :0040C707 8BEC                    mov ebp, esp

 y como ahi podeis ver es llamada desde 5 sitios.
 Poniendo sendos puntos de ruptura en esos cinco sitios i uno mas en la
 instruccion donde se daba el fallo de pagina por si acaso (0040C773), vemos
 k el programa arranca sin parar en ninguno de ellos.

 Ahora hacemos la misma prueba para el ejecutable modificado, y  vemos k para
 en el el punto situado en la VA 0040B831, seguidamente en la VA 0040C74B, i
 despues se produce la excepcion. Asi k tenemos k llegamos a la VA 0040B831
 cuando no habriamos debido llegar.

 :0040B827 8BF8                    mov edi, eax
 :0040B829 85FF                    test edi, edi
 :0040B82B 7409                    je 0040B836
 :0040B82D 6A01                    push 00000001
 :0040B82F 8BCF                    mov ecx, edi
 :0040B831 E8CA0E0000              call 0040C700 <- no debemos llegar

 primera posibilidad para no llegar.... k se ejecute el salto  condicional k
 hay en 0040b82b, pero resulta ke esa instruccion tampoco se llega a ejecutar
 en la version sin modificacion. Por lo tanto, este no es el punto ke
 buscamos.

 :0040B7FE 83E007                  and eax, 00000007
 :0040B801 390C85C0FC4500          cmp dword ptr [4*eax+0045FCC0], ecx
 :0040B808 7470                    je 0040B87A
 :0040B80A 833D1C03460000          cmp dword ptr [0046031C], 00000000
 :0040B811 7E2A                    jle 0040B83D
 :0040B813 6A04                    push 00000004
 :0040B815 E8C9980200              call 004350E3

 Un poco mas arriba encontramos esas otras dos instrucciones de flujo, en
 las VAs 0040B808 y 0040B811. El ejecutable sin modificaciones, para el el
 punto de ruptura puesto en 0040B808, pero ademas, solo para una vez, i el
 salto se ejecuta. Si ponemos un punto de ruptura en 0040B808, ahora en el
 ejecutable modificado, vemos ke ese salto tambien se ejecuta pero en este
 caso no salta. Asi k la modificacion k tendriamos ke hacer, seria cambiar
 ese salto condicional por uno incondiconal. Asi pues, con el editor
 hexadecimal buscamos la cadena

                          39 0C 85 C0 FC 45 00 74 70
 y la cambiamos por:
			  39 0C 85 C0 FC 45 00 EB 70

 Recordaros k el otro cambio k habiamos hecho, era el del salto condicionaL
 k habia para comprobar la fecha, y las cadenas k habiamos cambiado eran:

                          3D A0 DA 05 00 7C 07 8B CE
 por:
			  3D A0 DA 05 00 EB 07 8B CE

 y ahora el programa funciona perfectamente :)

 Pues espero k os haya kedao claro.... evite intencionadamente entrar en el
 estudio detallado de la rutina de proteccion, basikamente porke es un peazo
 :).....





5.- ESTO ES TODO AMIGOS.


Pues creo ke esto es todo por ahora...la verdad es ke tarde algo mas de lo ke
esperaba en terminar este texto... Pero al final lo termine no?

Saludos a Lykeios y tambien a telrauko, k se han leido por adelantado trozos
del articulo i kuyos valiosos comentarios han contribuido a mejorar el
contenido del articulo, y a ke se terminase unos meses antes de lo ke se
hubiese terminado si no se me diese alguien tanto la vara ( verdad, lyk?)

Y tambien comentar ke mucha gente abordo ya estos temas con anterioridad, y
sus trabajos se pueden encontrar por inte... no voy a citar a todas las
personas de las ke he leido articulos sobre este mismo tema pork la lista es
larga, i seguramente haya aun mucho mas ke no llego a caer en mis manos...
pero nombrare algunos, ke se me vienen ahora mismo a la mente... como  por
ejemplo NuMIT_or, Iczelion, Demian, R!SC, Net Walker..... la lista es muy
larga...
Hay mucho i muy bueno ( mejor ke esto) por la red...
ya sabeis, el conocimiento esta a vuestro alcance....


ah!... y muchas gracias por todo a CatWoman :@@@

-=(EOF)=-
